﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PayloadTracker.Tiles
{
    class TileManager
    {

        public event TileInvalidatedDelegate TileInvalidated;
        ProviderConfiguration m_Config;
        struct CacheEntry
        {
            public ITileProvider.TileKey Key;
            public Tile Tile;
            public DateTime Accessed;
        }
        Dictionary<string, Dictionary<string,Tile>> m_Cache;
        public TileManager()
        {
            m_Cache = new Dictionary<string, Dictionary<string, Tile>>() ;
            m_Config = ProviderConfiguration.Load(Settings.Default["TileProvidersFile"] as string);
        }
        public List<List<Tile>> GetTilesForRegion(Coordinate UL, Coordinate LR, int Zoom, bool Async)
        {
            List<List<Tile>> ret = new List<List<Tile>>();



            Dictionary<string, Dictionary<string, Tile>> NewCache = new Dictionary<string,Dictionary<string,Tile>>();

            foreach (var tp in GetAllEnabledProviders())
            {
                var keys = tp.GetUniqueKeysForRegion(UL, LR, Zoom);
                List<Tile> pTiles = new List<Tile>();
                string ID = tp.Name();

                if (!m_Cache.ContainsKey(ID))
                    m_Cache.Add(ID, new Dictionary<string, Tile>());

                if (!NewCache.ContainsKey(ID))
                    NewCache.Add(ID, new Dictionary<string, Tile>());


                foreach (var k in keys)
                {
                    string hash = k.GetHash();
                    if (m_Cache[ID].ContainsKey(hash))
                    {
                        pTiles.Add(m_Cache[ID][hash]);
                        NewCache[ID].Add(hash, m_Cache[ID][hash]);

                    }
                    else
                    {
                        var tile = tp.GetTileFromKey(k, Async);
                        tile.OnTileInvalidated += new TileInvalidatedDelegate(tile_OnTileInvalidated);
                        //m_Cache[ID].Add(hash, tile);
                        NewCache[ID].Add(hash, tile);
                        pTiles.Add(tile);
                    }
                }
                

                if(pTiles.Count > 0)
                    ret.Add(pTiles);
            }

            m_Cache = NewCache;
            GC.Collect(2, GCCollectionMode.Optimized);

            return ret;
        }

        void tile_OnTileInvalidated(Tile t)
        {
            var handler = TileInvalidated;
            if (handler != null)
                handler(t);
        }

        private IEnumerable<ITileProvider> GetAllEnabledProviders()
        {
            return (from p in m_Config.TileProviders where p.Enabled select p);
        }
    }
}
